/**
 *
 *      ___                       ___
 *     /\  \          ___        /\  \
 *    /::\  \        /\  \      /::\  \
 *   /:/\:\  \       \:\  \    /:/\ \  \
 *  /:/  \:\  \      /::\__\  _\:\~\ \  \
 * /:/__/ \:\__\  __/:/\/__/ /\ \:\ \ \__\
 * \:\  \  \/__/ /\/:/  /    \:\ \:\ \/__/
 *  \:\  \       \::/__/      \:\ \:\__\
 *   \:\  \       \:\__\       \:\/:/  /
 *    \:\__\       \/__/        \::/  /
 *     \/__/                     \/__/
 *
 * CIS - Clang Indexing Service is a Project Manager & Source code indexing service
 * created so as to simplify the indexing of C/C++ based source code which use
 * standardized build mechanisms.
 *
 **/

#include "../includes/requestprocessor.hxx"
#include "../includes/request.hxx"
#include "../includes/cisexception.hxx"
#include "../includes/commands/buildprojectrequest.hxx"

#include <Poco/Logger.h>
#include <Poco/LogStream.h>
#include <Poco/Dynamic/Var.h>
#include <typeinfo>
#include <Poco/JSON/Array.h>
#include <sstream>

#include <Poco/JSON/Object.h>
#include <Poco/JSON/Parser.h>
#include <Poco/JSON/Query.h>
#include <Poco/JSON/JSONException.h>
#include <Poco/JSON/Stringifier.h>
#include <Poco/JSON/DefaultHandler.h>
#include <Poco/JSON/Template.h>

using namespace cis;
using namespace Poco::JSON;
using namespace Poco::Dynamic;

namespace {
Poco::Logger& logger = Poco::Logger::get("JsonRequestProcessor");
Poco::LogStream logstream(logger);

std::string getJsonFromException(const Poco::Exception& e)
{
    std::stringstream returnval;
    returnval << "{\"error\" : { \"message\" : \"" <<  e.displayText() << "\"}, \"id\" : null}" << std::endl;
    return returnval.str();
}

std::string getJsonFromException(const std::string& str)
{
    std::stringstream returnval;
    returnval << "{\"error\" : { \"message\" : \"" <<  str << "\"}, \"id\" : null}" << std::endl;
    return returnval.str();
}
}

Poco::DynamicFactory<Request> RequestProcessor::commandFactory;

RequestProcessor::RequestProcessor()
{
}

std::string RequestProcessor::execute(const std::string& request)
{
    Parser parser;
    Var result;
    try {
        DefaultHandler handler;
        parser.setHandler(&handler);
        parser.parse(request);
        result = handler.result();
        Object::Ptr ptr = result.extract<Object::Ptr > ();

        Var methodvar = ptr->get("method");
        if (methodvar.isEmpty() || !methodvar.isString())
            throw cis::InvalidRequestException("method not found on the request");
        std::string method = methodvar.convert<std::string>();

        Var paramsvar = ptr->get("params");
        if (paramsvar.isEmpty() || !paramsvar.isString())
            throw cis::InvalidRequestException("params not found on the request");
        std::string params = paramsvar.convert<std::string>();

        Var idvar = ptr->get("id");
        if (idvar.isEmpty() || !idvar.isInteger())
            throw cis::InvalidRequestException("id not found on the request");
        int id = idvar.convert<int>();

        logstream.debug() << "request for {method : " << method
                          << ", params : " << params << ", id : "
                          << id << "}" << std::endl;
        try {
            Poco::SharedPtr<Request> request = commandFactory.createInstance(method);
            return request->execute(params);
        } catch (const Poco::NotFoundException& e) {
            std::string err = "Command not found - " + e.message();
            logstream.error() << err << std::endl;
             return getJsonFromException(err);
        }
        
    } catch (const cis::Exception& e) {
        logstream.error() << "Exception parsing user request [" << e.message() << "]." << std::endl;
        return getJsonFromException(e);
    }
}

RequestProcessor::~RequestProcessor()
{
}

